﻿
Imports System.ComponentModel
Imports System.Runtime.CompilerServices
Imports System.Net
Imports System.IO
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Imports Tunlr.Settings
Imports System.Management
Imports System.Collections.ObjectModel
Imports System.Windows.Threading
Imports System.Windows.Forms
Imports ginkyo.AdvancedApi.WPFApplication

Public Class MainModel
    Implements INotifyPropertyChanged
    Public Event PropertyChanged As PropertyChangedEventHandler _
    Implements INotifyPropertyChanged.PropertyChanged
    Private Sub NotifyPropertyChanged(<CallerMemberName()> Optional ByVal propertyName As String = Nothing)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub

    Public AppSettings As New Settings

#Region "Properties"

    Private _interfaces As New ObservableCollection(Of NetworkInterface)
    <Browsable(False)> _
    Public Property Interfaces() As ObservableCollection(Of NetworkInterface)
        Get
            Return _interfaces
        End Get
        Set(ByVal value As ObservableCollection(Of NetworkInterface))
            _interfaces = value
            NotifyPropertyChanged()
        End Set
    End Property

    Public Property SelectedInterface() As NetworkInterface
        Get
            Return GetInterfaceFromNIC(AppSettings.NIC)
        End Get
        Set(value As NetworkInterface)

            If value IsNot Nothing Then
                AppSettings.NIC = value.NIC
                If SyncEnable Then
                    SynTunlrDNS()
                Else
                    Status = CheckingStatus.Local
                End If
            Else
                Status = CheckingStatus.Local
            End If


            NotifyPropertyChanged("SelectedInterface")
        End Set
    End Property

    Private _tunlrDNS As TunlrDNS
    <Browsable(False)> _
    Public Property TunlrDNS() As TunlrDNS
        Get
            Return _tunlrDNS
        End Get
        Set(ByVal value As TunlrDNS)
            _tunlrDNS = value
            NotifyPropertyChanged()
        End Set
    End Property

#Region "Application Properties"

    Public ReadOnly Property ReleaseDate() As String
        Get
            Return ginkyo.AdvancedApi.WPFApplication.ApplicationProperties.ProductReleaseDate
        End Get
    End Property

    Public ReadOnly Property Version() As System.Version
        Get
            Return ginkyo.AdvancedApi.WPFApplication.ApplicationProperties.ProductVersion
        End Get
    End Property

    Public ReadOnly Property ThanksTo() As String
        Get
            Return "Marilia Rodrigues"
        End Get
    End Property

    Public Enum CheckingStatus
        Local
        Syncing
        Synced
        [Error]
    End Enum

    Private _status As CheckingStatus
    <Browsable(False)> _
    Public Property Status() As CheckingStatus
        Get
            Return _status
        End Get
        Set(ByVal value As CheckingStatus)
            _status = value
            If value <> CheckingStatus.Error Then
                _SyncDebug = String.Empty
            End If

            NotifyPropertyChanged()
        End Set
    End Property

    Public Property SyncEnable() As Boolean
        Get
            Return AppSettings.AutoSync
        End Get
        Set(value As Boolean)
            AppSettings.AutoSync = value

            If value Then
                SynTunlrDNS()
            Else
                If Not SelectedInterface Is Nothing Then SelectedInterface.ClearDNS = True : NotifyPropertyChanged("SelectedInterface") : Status = CheckingStatus.Local
            End If

            NotifyPropertyChanged()
        End Set

    End Property

#End Region

#End Region

#Region "Functions"
#Region "Tunlr"

    Private _SyncDebug As String = ""

    Public Async Function LoadTunlrDNS() As Task(Of TunlrDNS)
        Try
            TunlrDNS = Await GetDNS()

            Return TunlrDNS

        Catch ex As Exception

            _SyncDebug = ex.Message

            Return Nothing
        End Try

    End Function

    Private Async Function GetDNS() As Task(Of TunlrDNS)

        Dim _request As HttpWebRequest = DirectCast(WebRequest.Create(URLRequestDNS), HttpWebRequest)
        _request.Method = "GET"
        Try

            Dim _response = Await _request.GetResponseAsync

            _SyncDebug = String.Empty

            Return ParseJson(Of TunlrDNS)(New StreamReader(_response.GetResponseStream()).ReadToEnd)

        Catch ex As WebException

            _SyncDebug = ex.Message

            Return Nothing

        End Try

    End Function

    Friend Shared Function ParseJson(Of T)(json As String) As T
        Dim jobject__1 = JObject.Parse(json)
        Return JsonConvert.DeserializeObject(Of T)(jobject__1.ToString)
    End Function

#End Region

#Region "NetworkInteraces"


    Public Sub LoadNetworkInterfaces()


        Interfaces.Clear()
        For Each Card In GetAdapters()
            Interfaces.Add(New NetworkInterface(Card))
        Next

        SelectedInterface = GetInterfaceFromNIC(AppSettings.NIC)

    End Sub

    Private Function GetAdapters() As System.Management.ManagementObjectCollection

        Dim adapters As ManagementObjectSearcher = New ManagementObjectSearcher(New ObjectQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = TRUE"))
        Return adapters.Get

    End Function

    Public Function GetInterfaceFromNIC(NIC As String) As NetworkInterface
        Try

            Try



                Dim _ToReturn = (From Intr As NetworkInterface In Interfaces Where Intr.NIC = NIC Select Intr).FirstOrDefault
                If _ToReturn IsNot Nothing Then

                    Return Interfaces.FirstOrDefault

                Else

                    Return Nothing

                End If

            Catch ex As Exception

                Return Nothing

            End Try

        Catch ex As Exception

            Return Nothing

        End Try

    End Function


#End Region


    Public Async Function SynTunlrDNS() As Task(Of Boolean)
        Try
retry:

            Status = CheckingStatus.Syncing

            If SelectedInterface Is Nothing Then

                NotifyPropertyChanged("SelectedInterface")
                Status = CheckingStatus.Local

                Return True

            End If


            Dim _tmpDNSServers As TunlrDNS = Await LoadTunlrDNS()
            If _tmpDNSServers IsNot Nothing Then

                Try

                    SelectedInterface.PrimaryDNS = _tmpDNSServers.PrimaryDNS
                    SelectedInterface.SecondaryDNS = _tmpDNSServers.SecondaryDNS
                    Status = CheckingStatus.Synced

                    Return True

                Catch ex As Exception

                    LoadNetworkInterfaces()
                    GoTo retry

                End Try

            Else

                If My.Computer.Network.IsAvailable Then

                    SelectedInterface.ClearDNS = True

                    Status = CheckingStatus.Local

                    Return False
                Else

                    LoadNetworkInterfaces()
                    GoTo retry

                End If

            End If

        Catch ex As Exception

            If My.Computer.Network.IsAvailable Then

                SelectedInterface.ClearDNS = True

                Status = CheckingStatus.Local


                _SyncDebug = ex.Message

                Return False

            Else

                LoadNetworkInterfaces()
                GoTo retry

            End If

        End Try
    End Function

    Public Sub Sync()
        Task.Run(Async Function()

                     Do While True

                         If SyncEnable = False Or SelectedInterface Is Nothing Then

                             If My.Computer.Network.IsAvailable And SelectedInterface Is Nothing Then

                                 LoadNetworkInterfaces()

                             Else

                                 Status = CheckingStatus.Local
                                 If Not SelectedInterface Is Nothing Then
                                     SelectedInterface.ClearDNS = True
                                 End If

                             End If
                         Else


                             Await SynTunlrDNS()


                         End If


                         For i As Integer = 0 To AppSettings.CheckInterval.TotalMilliseconds / 10
                             System.Threading.Thread.Sleep(10)
                         Next
                     Loop

                 End Function)

    End Sub


#End Region

#Region "Commands"

#Region "Main UI"

    Private _Command_ShowContextMenu As ICommand
    Private Function CanExecuteCommand_ShowContextMenu(ByVal param As Object) As Boolean
        Return True
    End Function
    Private Function ExecuteCommand_ShowContextMenu(ByVal parm As Object) As Task
        Dim _ToolbarContxt = Application.Current.FindResource("TrayIconContextMenu")
        _ToolbarContxt.Placement = Primitives.PlacementMode.Bottom
        _ToolbarContxt.PlacementTarget = parm
        _ToolbarContxt.IsOpen = True
    End Function
    Public ReadOnly Property Command_ShowContextMenu() As ICommand
        Get

            If _Command_ShowContextMenu Is Nothing Then
                _Command_ShowContextMenu = New RelayCommand(AddressOf ExecuteCommand_ShowContextMenu, AddressOf CanExecuteCommand_ShowContextMenu)
            End If

            Return _Command_ShowContextMenu
        End Get
    End Property

    Private _Command_ToggleSync As ICommand
    Private Function CanExecuteCommand_ToggleSync(ByVal param As Object) As Boolean
        Return SelectedInterface IsNot Nothing
    End Function
    Private Async Function ExecuteCommand_ToggleSync(ByVal parm As Object) As Task

        SyncEnable = Not SyncEnable

    End Function
    Public ReadOnly Property Command_ToggleSync() As ICommand
        Get

            If _Command_ToggleSync Is Nothing Then
                _Command_ToggleSync = New RelayCommand(AddressOf ExecuteCommand_ToggleSync, AddressOf CanExecuteCommand_ToggleSync)
            End If

            Return _Command_ToggleSync
        End Get
    End Property

    Private _Command_ShowDebug As ICommand
    Private Function CanExecuteCommand_ShowDebug(ByVal param As Object) As Boolean
        Return _SyncDebug <> String.Empty
    End Function
    Private Async Function ExecuteCommand_ShowDebug(ByVal parm As Object) As Task
        ginkyo.AdvancedApi.WPFApplication.MessageBox.Show(_SyncDebug, MessageBoxButton.OK, MessageBoxImage.Information)
    End Function
    Public ReadOnly Property Command_ShowDebug() As ICommand
        Get

            If _Command_ShowDebug Is Nothing Then
                _Command_ShowDebug = New RelayCommand(AddressOf ExecuteCommand_ShowDebug, AddressOf CanExecuteCommand_ShowDebug)
            End If

            Return _Command_ShowDebug
        End Get
    End Property

#End Region

#Region "ContextMenu"

    Private _Command_Exit As ICommand
    Private Function CanExecuteCommand_Exit(ByVal param As Object) As Boolean
        Return True
    End Function
    Private Async Function ExecuteCommand_Exit(ByVal parm As Object) As Task

        If ginkyo.AdvancedApi.WPFApplication.MessageBox.Show(String.Format("Do you realy want to Exit?{0}Exiting will set your DNS to Local", vbNewLine), MessageBoxButton.YesNo, MessageBoxImage.Question, , "Exit Tunlr Sync?", MessageBoxResult.No) = MessageBoxResult.Yes Then

            If Not SelectedInterface Is Nothing Then SelectedInterface.ClearDNS = True

            For Each item In Application.Current.Windows
                item.close()
            Next

        End If

    End Function
    Public ReadOnly Property Command_Exit() As ICommand
        Get

            If _Command_Exit Is Nothing Then
                _Command_Exit = New RelayCommand(AddressOf ExecuteCommand_Exit, AddressOf CanExecuteCommand_Exit)
            End If

            Return _Command_Exit
        End Get
    End Property

    Private _Command_Settings As ICommand
    Private Function CanExecuteCommand_Settings(ByVal param As Object) As Boolean
        Return True
    End Function
    Private Async Function ExecuteCommand_Settings(ByVal parm As Object) As Task

        Dim _settings As New SettingsView
        _settings.Settings = True
        _settings.Show()
        _settings = Nothing

    End Function
    Public ReadOnly Property Command_Settings() As ICommand
        Get

            If _Command_Settings Is Nothing Then
                _Command_Settings = New RelayCommand(AddressOf ExecuteCommand_Settings, AddressOf CanExecuteCommand_Settings)
            End If

            Return _Command_Settings
        End Get
    End Property


    Private _Command_About As ICommand
    Private Function CanExecuteCommand_About(ByVal param As Object) As Boolean
        Return True
    End Function
    Private Async Function ExecuteCommand_About(ByVal parm As Object) As Task

        Dim _settings As New SettingsView
        _settings.About = True
        _settings.Show()
        _settings = Nothing

    End Function
    Public ReadOnly Property Command_About() As ICommand
        Get

            If _Command_About Is Nothing Then
                _Command_About = New RelayCommand(AddressOf ExecuteCommand_About, AddressOf CanExecuteCommand_About)
            End If

            Return _Command_About
        End Get
    End Property

    Private _Command_NIC As ICommand
    Private Function CanExecuteCommand_NIC(ByVal param As Object) As Boolean
        Return True
    End Function
    Private Async Function ExecuteCommand_NIC(ByVal parm As Object) As Task

        Dim _settings As New SettingsView

        LoadNetworkInterfaces()
        _settings.Nic = True
        _settings.Show()
        _settings = Nothing

    End Function
    Public ReadOnly Property Command_NIC() As ICommand
        Get

            If _Command_NIC Is Nothing Then
                _Command_NIC = New RelayCommand(AddressOf ExecuteCommand_NIC, AddressOf CanExecuteCommand_NIC)
            End If

            Return _Command_NIC
        End Get
    End Property

    Private _Command_Sync As ICommand
    Private Function CanExecuteCommand_Sync(ByVal param As Object) As Boolean
        Return SelectedInterface IsNot Nothing
    End Function
    Private Async Function ExecuteCommand_Sync(ByVal parm As Object) As Task
        SynTunlrDNS()
    End Function
    Public ReadOnly Property Command_Sync() As ICommand
        Get

            If _Command_Sync Is Nothing Then
                _Command_Sync = New RelayCommand(AddressOf ExecuteCommand_Sync, AddressOf CanExecuteCommand_Sync)
            End If

            Return _Command_Sync
        End Get
    End Property

#End Region

#End Region

















    Public Sub New()

        Sync()

    End Sub


End Class
